Skip to content

fix(bar): prevent outside text labels from overlapping tilted axis ticks - #7872

Open
vizansh wants to merge 6 commits into
plotly:masterfrom
vizansh:fix-bar-label-overlap
Open

fix(bar): prevent outside text labels from overlapping tilted axis ticks#7872
vizansh wants to merge 6 commits into
plotly:masterfrom
vizansh:fix-bar-label-overlap

Conversation

@vizansh

@vizansh vizansh commented Jun 27, 2026

Copy link
Copy Markdown

Fixes #7822

This pull request dynamically calculates the positioning for bar chart text labels when textposition='outside'.

Instead of using a static pixel margin, it looks up the active axis configuration and utilizes .getBBox() to measure the exact live dimensions of the tilted or long axis labels. It then shifts the bar numbers by that precise footprint plus a clean visual buffer, entirely preventing overlaps with the top/right axis ticks.

@camdecoster

Copy link
Copy Markdown
Contributor

Thanks for the PR! Our team will review and provide feedback.

@vizansh

vizansh commented Jul 14, 2026

Copy link
Copy Markdown
Author

Hi maintainers, could someone please approve and trigger the GitHub Actions workflow for this PR? I'd love to make sure all the automated CI/CD tests pass successfully. Thank you!

@camdecoster

Copy link
Copy Markdown
Contributor

Until we get to this review, could you please look into the test failures and see if anything is broken/needs to be updated?

@emilykl

emilykl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Hi @vizansh ! I just spent some time reviewing the original issue #7822, and posted a comment with my thoughts on the root cause and the best approach for a fix. I think the best fix will require a different approach than what you've done here.

Please feel free to continue working and pursue one of the fix approaches outlined in my comment if you like, or propose another approach. I'm happy to review.

@emilykl emilykl assigned vizansh and unassigned emilykl Jul 15, 2026
@vizansh

vizansh commented Jul 29, 2026

Copy link
Copy Markdown
Author

/review

Comment thread src/traces/bar/plot.js
Comment on lines +964 to +983
// Dynamic presentation safety buffer to clear tilted axis tick labels
var axisPad = 0;
if (!isHorizontal && opts.xa && opts.xa.side === 'top') {
if (opts.xa._g && opts.xa._g.node()) {
var axisBB = opts.xa._g.node().getBBox();
if (axisBB && axisBB.height > 0) {
// Shift exactly past the bounding height of the tilted labels plus a clean 6px visual gap
axisPad = axisBB.height + 6;
}
}
} else if (isHorizontal && opts.ya && opts.ya.side === 'right') {
if (opts.ya._g && opts.ya._g.node()) {
var axisBB = opts.ya._g.node().getBBox();
if (axisBB && axisBB.width > 0) {
// Shift exactly past the bounding width of the side labels plus a clean 6px visual gap
axisPad = axisBB.width + 6;
}
}
}

@emilykl emilykl Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this can all be removed now that the zeroBarDir logic has been added (please correct me if I'm missing something!). I tested it out locally and the issue seems resolved with just the zeroBarDir changes.

Along with removing the references to axisPad below

Suggested change
// Dynamic presentation safety buffer to clear tilted axis tick labels
var axisPad = 0;
if (!isHorizontal && opts.xa && opts.xa.side === 'top') {
if (opts.xa._g && opts.xa._g.node()) {
var axisBB = opts.xa._g.node().getBBox();
if (axisBB && axisBB.height > 0) {
// Shift exactly past the bounding height of the tilted labels plus a clean 6px visual gap
axisPad = axisBB.height + 6;
}
}
} else if (isHorizontal && opts.ya && opts.ya.side === 'right') {
if (opts.ya._g && opts.ya._g.node()) {
var axisBB = opts.ya._g.node().getBBox();
if (axisBB && axisBB.width > 0) {
// Shift exactly past the bounding width of the side labels plus a clean 6px visual gap
axisPad = axisBB.width + 6;
}
}
}

Comment thread src/traces/bar/plot.js
Comment on lines +989 to +992
targetX = x1 - dir * (textpad + axisPad);
anchorX = dir * extrapad;
} else {
targetY = y1 + dir * textpad;
targetY = y1 + dir * (textpad + axisPad);

@emilykl emilykl Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
targetX = x1 - dir * (textpad + axisPad);
anchorX = dir * extrapad;
} else {
targetY = y1 + dir * textpad;
targetY = y1 + dir * (textpad + axisPad);
targetX = x1 - dir * textpad;
anchorX = dir * extrapad;
} else {
targetY = y1 + dir * textpad;

Comment thread src/traces/bar/plot.js
Comment on lines 984 to +987
var dir = isHorizontal ? dirSign(x1, x0) : dirSign(y0, y1);
if ((isHorizontal ? x0 === x1 : y0 === y1) && opts.zeroBarDir) {
dir = opts.zeroBarDir;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is logically equivalent, just a style suggestion

Suggested change
var dir = isHorizontal ? dirSign(x1, x0) : dirSign(y0, y1);
if ((isHorizontal ? x0 === x1 : y0 === y1) && opts.zeroBarDir) {
dir = opts.zeroBarDir;
}
var dir;
if ((isHorizontal ? x0 === x1 : y0 === y1) && opts.zeroBarDir) {
dir = opts.zeroBarDir;
} else {
dir = isHorizontal ? dirSign(x1, x0) : dirSign(y0, y1);
}

Comment thread src/traces/bar/plot.js
plot: plot,
toMoveInsideBar: toMoveInsideBar
toMoveInsideBar: toMoveInsideBar,
toMoveOutsideBar: toMoveOutsideBar

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this can also be removed

Suggested change
toMoveOutsideBar: toMoveOutsideBar

.then(done, done.fail);
});

it('should keep zero-value outside labels on the same side as negative bars', function(done) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test!

Comment thread src/traces/bar/plot.js
Comment on lines +711 to +713
angle: angle,
xa: xa, // Pass the X-Axis configuration
ya: ya, // Pass the Y-Axis configuration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these are also no longer needed

Suggested change
angle: angle,
xa: xa, // Pass the X-Axis configuration
ya: ya, // Pass the Y-Axis configuration

@emilykl emilykl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vizansh Nice work! I think this is ready to merge once my comments are addressed.

Comment thread draftlogs/7872_fix.md
@@ -0,0 +1 @@
- Prevent outside bar text labels from overlapping tilted axis ticks [[#7872](https://github.com/plotly/plotly.js/pull/7872)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Prevent outside bar text labels from overlapping tilted axis ticks [[#7872](https://github.com/plotly/plotly.js/pull/7872)]
- Prevent outside bar text for zero-length bars from overlapping axis tick labels [[#7872](https://github.com/plotly/plotly.js/pull/7872)]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Bar labels overlap with top/right axis labels with textposition=outside

3 participants